//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//     Filename: XMLDoc.cpp                                                 //
//  Create date: April 02, 2004                                             //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//  Description: This file implements the XMLDoc class, which is a wrapper  //
//                 class for the Microsoft IID_IXMLDOMDocument2 interface.  //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
//       Copyright (c) 2004 - Realtime Gaming.  All rights reserved.        //
//////////////////////////////////////////////////////////////////////////////

#include "XMLDoc.h"
#include "log.h"

//////////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////////
XMLDoc::XMLDoc() : m_pXMLDoc( NULL ), m_pRoot( NULL )
{
}

//////////////////////////////////////////////////////////////////////////////
// Destructor
//////////////////////////////////////////////////////////////////////////////
XMLDoc::~XMLDoc()
{
	if ( m_pRoot )
	{
		m_pRoot->Release();
	}

    if ( m_pXMLDoc )
    {
        m_pXMLDoc->Release();
    }
}

//////////////////////////////////////////////////////////////////////////////
// Create
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::Create()
{
    bool8 bRetVal = false;
    
    // Create instance of XML DOM to use for parsing
    HRESULT hr = CoCreateInstance( CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, 
                                   IID_IXMLDOMDocument2, (void**)&m_pXMLDoc );

    if ( SUCCEEDED( hr ) )
    {
		m_pXMLDoc->put_preserveWhiteSpace( VARIANT_TRUE );
        bRetVal = true;
    }
    else
    {
        m_pXMLDoc = NULL;
    }

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// Save
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::Save( const String& sPath )
{
	bool8 bRetVal = false;

	if ( m_pXMLDoc )
	{
		_variant_t varString( sPath );
		HRESULT hr = m_pXMLDoc->save( varString );

		if ( SUCCEEDED( hr ) )
		{
			bRetVal = true;
		}
	}

	return bRetVal;
}


//////////////////////////////////////////////////////////////////////////////
// LoadXML
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::LoadXML( uint8* pBuffer )
{
    bool8 bRetVal = false;

    // Get rid of the m_pRoot if its there because we are about
    //  to discard the entire document if it's already been loaded
    if ( m_pRoot )
	{
		m_pRoot->Release();
        m_pRoot = NULL;
	}

    if ( m_pXMLDoc || Create() )
    {
        // Make sure we wait for all the XML to get loaded
        HRESULT hr = m_pXMLDoc->put_async( FALSE );

        if ( SUCCEEDED( hr ) )
        {
            _bstr_t bstrXML( (char*) pBuffer );
            VARIANT_BOOL bSuccess = FALSE;

            hr = m_pXMLDoc->loadXML( bstrXML, &bSuccess );

            if ( SUCCEEDED( hr ) && bSuccess )
            {
				// We need to recreate m_pRoot, since we just trashed it.
				hr = m_pXMLDoc->get_documentElement( &m_pRoot );
			}

			bRetVal = SUCCEEDED( hr ) && m_pRoot;
        }
    }

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// SendXML
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::SendXML( uint8* pBuffer, uint32 nBuffSize )
{
	bool8 bRetVal = false;

	if ( m_pXMLDoc )
	{
		BSTR bstrText;
		HRESULT hr = m_pXMLDoc->get_xml( &bstrText );

		if ( SUCCEEDED( hr ) )
		{
			// Assign to _bstr_t w/o copy, therefore the memory will get
			//  freed when this variable goes out of scope.
			_bstr_t bstrXML( bstrText, FALSE );

			// We are using UTF-8 encoding, so go ahead and copy the XML
			//   in 8 byte characters.
			strncpy( (char *) pBuffer, (char *) bstrXML, nBuffSize-1 );
			pBuffer[nBuffSize] = 0;

			bRetVal = true;
		}
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// GetSingeNodeText
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::GetSingleNodeText( const String& sQuery, String& sBuffer )
{
    bool8 bRetVal = false;

	if ( m_pXMLDoc || Create() )
	{
		IXMLDOMNode* pNode = NULL;
		HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sQuery), &pNode );

		if ( SUCCEEDED( hr ) && pNode )
		{
			// Get the text from the node
			BSTR bstrText;
			hr = pNode->get_text( &bstrText );
			
			// Assign to _bstr_t w/o copy, therefore the memory will get
			//  freed when this variable goes out of scope.
			_bstr_t bstrVal( bstrText, FALSE );

			// Copy into buffer passed in
			sBuffer = (wchar_t*) bstrVal;

			bRetVal = true;
		}

		if ( pNode )
		{
			pNode->Release();
		}
	}

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// GetSingleNodeByte
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::GetSingleNodeByte( const String& sQuery, uint8& nByteVal )
{
    bool8 bRetVal = false;

	if ( m_pXMLDoc || Create() )
	{
		IXMLDOMNode* pNode = NULL;
		HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sQuery), &pNode );

		if ( SUCCEEDED( hr) && pNode )
		{
			// Get the text from the node
			BSTR bstrText;
			hr = pNode->get_text( &bstrText );
			
			// Assign to _bstr_t w/o copy, therefore the memory will get
			//  freed when this variable goes out of scope.
			_bstr_t bstrVal( bstrText, FALSE );

			// Convert Text to integer
			nByteVal = _ttoi( LPCTSTR( bstrVal ) );

			bRetVal = true;
		}

		if ( pNode )
		{
			pNode->Release();
		}
	}

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// GetSingleNodeLong
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::GetSingleNodeLong( const String& sQuery, uint32& nLongVal )
{
    bool8 bRetVal = false;

	if ( m_pXMLDoc || Create() )
	{
		IXMLDOMNode* pNode = NULL;
		HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sQuery), &pNode );

		if ( SUCCEEDED( hr) && pNode )
		{
			// Get the text from the node
			BSTR bstrText;
			hr = pNode->get_text( &bstrText );
			
			// Assign to _bstr_t w/o copy, therefore the memory will get
			//  freed when this variable goes out of scope.
			_bstr_t bstrVal( bstrText, FALSE );

			// Convert Text to integer
			nLongVal = _ttol( LPCTSTR( bstrVal ) );

			bRetVal = true;
		}

		if ( pNode )
		{
			pNode->Release();
		}
	}

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// GetSingleNodeShort
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::GetSingleNodeShort( const String& sQuery, uint16& nShortVal )
{
    bool8 bRetVal = false;

	if ( m_pXMLDoc || Create() )
	{
		IXMLDOMNode* pNode = NULL;
		HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sQuery), &pNode );

		if ( SUCCEEDED( hr) && pNode )
		{
			// Get the text from the node
			BSTR bstrText;
			hr = pNode->get_text( &bstrText );
			
			// Assign to _bstr_t w/o copy, therefore the memory will get
			//  freed when this variable goes out of scope.
			_bstr_t bstrVal( bstrText, FALSE );

			// Convert Text to integer
			nShortVal = _ttoi( LPCTSTR( bstrVal ) );

			bRetVal = true;
		}

		if ( pNode )
		{
			pNode->Release();
		}
	}

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// GetSingleNodeShort
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::GetSingleNodeBool( const String& sQuery, bool8& bVal, bool8 bDefaultVal /* = false */ )
{
    bool8 bRetVal = false;

	if ( m_pXMLDoc || Create() )
	{
		IXMLDOMNode* pNode = NULL;
		HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sQuery), &pNode );

		if ( SUCCEEDED( hr) && pNode )
		{
			// Get the text from the node
			BSTR bstrText;
			hr = pNode->get_text( &bstrText );
			
			// Assign to _bstr_t w/o copy, therefore the memory will get
			//  freed when this variable goes out of scope.
			_bstr_t bstrVal( bstrText, FALSE );

			if ( (bstrVal == _bstr_t("True")) || (bstrVal == _bstr_t("true")) )
			{
				bVal = true;
			}
			else if ( (bstrVal == _bstr_t("False")) || (bstrVal == _bstr_t("false")) )
			{
				bVal = false;
			}
			else
			{
				ASSERT(false);
				bVal = bDefaultVal;
			}

			bRetVal = true;
		}

		if ( pNode )
		{
			pNode->Release();
		}
	}

    return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddProcessingInstruction
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddProcessingInstruction( const String& sInstruction )
{
	bool8 bRetVal = false;

	if ( m_pXMLDoc || Create() )
	{
		// Set correct text
		_bstr_t bstrText;
		if ( !sInstruction.isEmpty() )
		{
			bstrText = sInstruction;
		}
		else
		{
			bstrText = "version=\"1.0\" encoding=\"UTF-8\"";
		}

		// Create the instruction
		IXMLDOMProcessingInstruction* pIns;
		HRESULT hr = m_pXMLDoc->createProcessingInstruction( _bstr_t("xml"), bstrText, &pIns );
		if ( SUCCEEDED( hr ) )
		{
			IXMLDOMNode *pNode = NULL;
			hr = m_pXMLDoc->appendChild( pIns, &pNode );

			if ( SUCCEEDED( hr ) && pNode )
			{
				bRetVal = true;
			}

			// Release references
			if ( pIns )
			{
				pIns->Release();
			}
			if ( pNode )
			{
				pNode->Release();
			}
		}
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// StartNew
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::StartNew()
{
	return AddProcessingInstruction( TEXT("") );
}

//////////////////////////////////////////////////////////////////////////////
// CreateRootNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::CreateRootNode( const String& sName )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot == NULL );
	ASSERT( m_pXMLDoc );

	HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &m_pRoot );

	if ( SUCCEEDED( hr ) && m_pRoot )
	{
		IXMLDOMNode *pNode = NULL;
		hr = m_pXMLDoc->appendChild( m_pRoot, &pNode );

		if ( SUCCEEDED( hr ) && pNode )
		{
			bRetVal = true;
		}
		else
		{
			m_pRoot->Release();
			m_pRoot = NULL;
		}

		// Release reference
		if ( pNode )
		{
			pNode->Release();
		}

		// Don't release the root - we are going to keep it around and
		//   release it in the destructor.
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddRootChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddRootChildNode( const String& sName )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );
	
	IXMLDOMElement* pNewNode = NULL;
	HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
	if ( SUCCEEDED( hr ) && pNewNode )
	{
		IXMLDOMNode *pNode = NULL;
		hr = m_pRoot->appendChild( pNewNode, &pNode );
		
		if ( SUCCEEDED( hr ) && pNode )
		{
			bRetVal = true;
		}

		if ( pNode )
		{
			pNode->Release();
		}
	}

	if ( pNewNode )
	{
		pNewNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddRootChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddRootChildNode( const String& sName, const String& sValue )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );
	
	IXMLDOMElement* pNewNode = NULL;
	HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
	if ( SUCCEEDED( hr ) && pNewNode )
	{
		hr = pNewNode->put_text( _bstr_t(sValue) );
		if ( SUCCEEDED( hr ) )
		{
			IXMLDOMNode *pNode = NULL;
			hr = m_pRoot->appendChild( pNewNode, &pNode );
			
			if ( SUCCEEDED( hr ) && pNode )
			{
				bRetVal = true;
			}

			if ( pNode )
			{
				pNode->Release();
			}
		}
	}

	if ( pNewNode )
	{
		pNewNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddRootChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddRootChildNode( const String& sName, uint32 nValue )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );

	// Convert value to string
	String sValue;
	sValue.sprintf( "%d", nValue );
	
	// Create the new node
	IXMLDOMElement* pNewNode = NULL;
	HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
	if ( SUCCEEDED( hr ) && pNewNode )
	{
		hr = pNewNode->put_text( _bstr_t(sValue) );
		if ( SUCCEEDED( hr ) )
		{
			IXMLDOMNode *pNode = NULL;
			hr = m_pRoot->appendChild( pNewNode, &pNode );
			
			if ( SUCCEEDED( hr ) && pNode )
			{
				bRetVal = true;
			}

			if ( pNode )
			{
				pNode->Release();
			}
		}
	}

	if ( pNewNode )
	{
		pNewNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddRootChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddRootChildNode( const String& sName, bool8 bValue )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );

	// Convert value to string
	_bstr_t bstrValue;
	
	if ( bValue )
	{
		bstrValue = _T("True");
	}
	else
	{
		bstrValue = _T("False");
	}

	// Create the new node
	IXMLDOMElement* pNewNode = NULL;
	HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
	if ( SUCCEEDED( hr ) && pNewNode )
	{
		hr = pNewNode->put_text( bstrValue );
		if ( SUCCEEDED( hr ) )
		{
			IXMLDOMNode *pNode = NULL;
			hr = m_pRoot->appendChild( pNewNode, &pNode );
			
			if ( SUCCEEDED( hr ) && pNode )
			{
				bRetVal = true;
			}

			if ( pNode )
			{
				pNode->Release();
			}
		}
	}

	if ( pNewNode )
	{
		pNewNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddRootChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddRootChildNode( const String& sName, const Card& c )
{
	String sCard;

	if ( c == Card((uint8)0) )
	{
		sCard += String::Character('0');
	}
	else
	{
		sCard += String::Character(c.getRankChar());

		//psharpless 10/16/06
		//joker's are currently coming across as a suitless ace, therefor
		//we cannot assume that there will always be a suit character

		if(c.getSuitChar())
			sCard += String::Character(c.getSuitChar());
	}

	return AddRootChildNode( sName, sCard );
}

//////////////////////////////////////////////////////////////////////////////
// AddChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddChildNode( const String& sParentQuery, const String& sName )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );

	IXMLDOMNode* pParentNode = NULL;
	HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sParentQuery), &pParentNode );

	if ( SUCCEEDED( hr) && pParentNode )
	{		
		// Create the new node
		IXMLDOMElement* pNewNode = NULL;
		HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
		if ( SUCCEEDED( hr ) && pNewNode )
		{
			IXMLDOMNode *pNode = NULL;
			hr = pParentNode->appendChild( pNewNode, &pNode );
			
			if ( SUCCEEDED( hr ) && pNode )
			{
				bRetVal = true;
			}

			if ( pNode )
			{
				pNode->Release();
			}
		}

		if ( pNewNode )
		{
			pNewNode->Release();
		}
	}

	if ( pParentNode )
	{
		pParentNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddChildNode( const String& sParentQuery, const String& sName, uint32 nValue )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );

	IXMLDOMNode* pParentNode = NULL;
	HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sParentQuery), &pParentNode );

	if ( SUCCEEDED( hr) && pParentNode )
	{
		// Convert value to string
		String sValue;
		sValue.sprintf( "%d", nValue );
		
		// Create the new node
		IXMLDOMElement* pNewNode = NULL;
		HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
		if ( SUCCEEDED( hr ) && pNewNode )
		{
			hr = pNewNode->put_text( _bstr_t(sValue) );
			if ( SUCCEEDED( hr ) )
			{
				IXMLDOMNode *pNode = NULL;
				hr = pParentNode->appendChild( pNewNode, &pNode );
				
				if ( SUCCEEDED( hr ) && pNode )
				{
					bRetVal = true;
				}

				if ( pNode )
				{
					pNode->Release();
				}
			}
		}

		if ( pNewNode )
		{
			pNewNode->Release();
		}
	}

	if ( pParentNode )
	{
		pParentNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddChildNode( const String& sParentQuery, const String& sName, const String& sValue )
{
	bool8 bRetVal = false;

	ASSERT( m_pXMLDoc );

	IXMLDOMNode* pParentNode = NULL;
	HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sParentQuery), &pParentNode );

	if ( SUCCEEDED( hr) && pParentNode )
	{
		// Create the new node
		IXMLDOMElement* pNewNode = NULL;
		HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
		if ( SUCCEEDED( hr ) && pNewNode )
		{
			hr = pNewNode->put_text( _bstr_t(sValue) );
			if ( SUCCEEDED( hr ) )
			{
				IXMLDOMNode *pNode = NULL;
				hr = pParentNode->appendChild( pNewNode, &pNode );
				
				if ( SUCCEEDED( hr ) && pNode )
				{
					bRetVal = true;
				}

				if ( pNode )
				{
					pNode->Release();
				}
			}
		}

		if ( pNewNode )
		{
			pNewNode->Release();
		}
	}

	if ( pParentNode )
	{
		pParentNode->Release();
	}

	return bRetVal;
}



//////////////////////////////////////////////////////////////////////////////
// AddChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddChildNode( const String& sParentQuery, const String& sName, bool8 bValue )
{
	bool8 bRetVal = false;

	ASSERT( m_pRoot != NULL );
	ASSERT( m_pXMLDoc );

	IXMLDOMNode* pParentNode = NULL;
	HRESULT hr = m_pXMLDoc->selectSingleNode( _bstr_t(sParentQuery), &pParentNode );

	// Convert value to string
	_bstr_t bstrValue;
	
	if ( bValue )
	{
		bstrValue = _T("True");
	}
	else
	{
		bstrValue = _T("False");
	}

	if ( SUCCEEDED( hr) && pParentNode )
	{
		// Create the new node
		IXMLDOMElement* pNewNode = NULL;
		HRESULT hr = m_pXMLDoc->createElement( _bstr_t(sName), &pNewNode );
		if ( SUCCEEDED( hr ) && pNewNode )
		{
			hr = pNewNode->put_text( bstrValue );
			if ( SUCCEEDED( hr ) )
			{
				IXMLDOMNode *pNode = NULL;
				hr = pParentNode->appendChild( pNewNode, &pNode );
				
				if ( SUCCEEDED( hr ) && pNode )
				{
					bRetVal = true;
				}

				if ( pNode )
				{
					pNode->Release();
				}
			}
		}

		if ( pNewNode )
		{
			pNewNode->Release();
		}
	}

	if ( pParentNode )
	{
		pParentNode->Release();
	}

	return bRetVal;
}

//////////////////////////////////////////////////////////////////////////////
// AddChildNode
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::AddChildNode( const String& sParentQuery, const String& sName, const Card& c )
{
	String sCard;

	if ( c == Card((uint8)0) )
	{
		sCard += String::Character('0');
	}
    // This indicates a joker
    else if ( c == Card((uint8)1) )
    {
		sCard = TEXT("Joker");
    }
	else
	{
		sCard += String::Character(c.getRankChar());
		sCard += String::Character(c.getSuitChar());
	}

	return AddChildNode( sParentQuery, sName, sCard );
}

//////////////////////////////////////////////////////////////////////////////
// ReplaceRootChildNode
// Replaces the value of the root's child node with the name "sName" with "sValue"
// Returns true if the value is replaced
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::ReplaceRootChildNode( const String& sName, const String& sValue )
{
	if ( RemoveRootChildNode( sName ) )
	{
		return AddRootChildNode( sName, sValue );
	}

	return false;
}

//////////////////////////////////////////////////////////////////////////////
// ReplaceRootChildNode
// Replaces the value of the root's child node with the name "sName" with "nValue"
// Returns true if the value is replaced
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::ReplaceRootChildNode( const String& sName, uint32 nValue )
{
	if ( RemoveRootChildNode( sName ) )
	{
		return AddRootChildNode( sName, nValue );
	}

	return false;
}

//////////////////////////////////////////////////////////////////////////////
// ReplaceRootChildNode
// Replaces the value of the root's child node with the name "sName" with "bValue"
// Returns true if the value is replaced
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::ReplaceRootChildNode( const String& sName, bool8 bValue )
{
	if ( RemoveRootChildNode( sName ) )
	{
		return AddRootChildNode( sName, bValue );
	}
	
	return false;
}

//////////////////////////////////////////////////////////////////////////////
// ReplaceRootChildNode
// Replaces the value of the root's child node with the name "sName" with "c"
// Returns true if the value is replaced
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::ReplaceRootChildNode( const String& sName, const Card& c )
{
	if ( RemoveRootChildNode( sName ) )
	{
		return AddRootChildNode( sName, c );
	}
	
	return false;
}

//////////////////////////////////////////////////////////////////////////////
// RemoveRootChildNode
// Removes the root's child node with the name "sName"
// Returns true if the node is removed, or was not found to begin with.
//////////////////////////////////////////////////////////////////////////////
bool8 XMLDoc::RemoveRootChildNode( const String& sName)
{
    bool8 bRetVal = false;

    if ( !m_pXMLDoc )
		return false;

    if ( !m_pRoot )
		return false;

	IXMLDOMNode* pChildNode = NULL;
	HRESULT hr = m_pRoot->selectSingleNode( _bstr_t(sName), &pChildNode );

	if ( SUCCEEDED(hr) && pChildNode )
	{
		hr = m_pRoot->removeChild( pChildNode, NULL );
        bRetVal = SUCCEEDED( hr );

        // Release the node found using selectSingleNode
        pChildNode->Release();
	}
    else
    {
	    //  No node to remove - we'll call this success, since the end result is the same
        bRetVal = true;
    }

	return bRetVal;
}